/**
 * A panel that can contain a Photo Object.
 * Video and Photo are too much different (JFM and not) to have the same panel (now at least)
 * Allows drag and drop of images (if enabled)
 * 
 * @author remo.lemma@lu.unisi.ch
 */

package ch.unisi.inf.projects.java.uom.gui.itemeditor.multimedia;

import java.awt.*;

import javax.swing.*;

import java.awt.datatransfer.*;
import java.awt.dnd.*;
import java.awt.event.*;
import java.io.*;
import java.awt.image.*;
import java.util.List;
import java.util.ArrayList;
import javax.imageio.ImageIO;

import ch.unisi.inf.projects.java.uom.elements.*;
import ch.unisi.inf.projects.java.uom.gui.commands.*;
import ch.unisi.inf.projects.java.uom.gui.UOMImages;

public final class PhotoPanel extends JComponent {

	/** We are not going to serialize this class atm */
	private static final long serialVersionUID = -1L;
	
	/** The width of the panel */
	private int width;
	
	/** The height of the panel */
	private int height;
	
	/** The content of the panel */
	private Photo content;
	
	/** List of listners */
	private List<PhotoPanelListener> listeners;
		
	/** Constructor
	 * @param width the width of the panel
	 * @param height the height of the panel
	 */
	public PhotoPanel (final int width, final int height)
	{
		this.height = height;
		this.width = width;
		content = null;
		listeners = new ArrayList<PhotoPanelListener>();
	}
	
	/**
	 * Sets the content of the panel
	 * @param content the Photo to be displayed
	 */
	public void setContent (final Photo content)
	{
		this.content = content;
		fireNewContentDisplayed(content);
		this.repaint();
	}
	
	public void forceNotifyDelete (final Photo photo)
	{
		firePhotoRemoved(photo);
	}
	
	public Photo getContent ()
	{
		return this.content;
	}
	
	/**
	 * Paints the contents
	 * @param g the Graphics component
	 */
	public void paintComponent (Graphics g)
	{
		final Dimension current = this.getSize();
		if (current.getHeight() != 0.0)
			height = (int) current.getHeight();
		if (current.getWidth() != 0.0)
			width = (int) current.getWidth();
		final Dimension size = this.getSize();
		g.clearRect(0, 0, size.width, size.height);

		BufferedImage newImage = null;
		BufferedImage image = null;
		
		if (content == null || content.view() == null)
			try {
				if (ItemManager.instance().databaseIsOpen()) {
					image = ImageIO.read(getClass().getResource(UOMImages.EMPTYPANEL.getFileName()));
				}
				else {
					newImage = new BufferedImage(1,1,BufferedImage.TYPE_INT_RGB);
					g.drawImage(newImage, 0, 0, null);
					return;
				}
			}
			catch (final IOException ioe)
			{
				newImage = new BufferedImage(1,1,BufferedImage.TYPE_INT_RGB);
				g.drawImage(newImage, 0, 0, null);
				return;
			}
			if (image == null)
				image = content.view();
			final int iwidth = image.getWidth();
			final int iheight = image.getHeight();
			final double scale = Math.max((1.0 * iwidth) / width, (1.0 * iheight) / height);
		
			newImage = new BufferedImage((int) Math.floor(iwidth / scale), (int) Math.floor(iheight / scale), BufferedImage.TYPE_INT_RGB);
			for(int y = 0; y < iheight/scale; y++) {
				for(int x = 0; x < iwidth/scale; x++) {
					if (Math.floor(x * scale) > iwidth || Math.floor(y * scale) > iheight)
						continue;
					try {
						newImage.setRGB(x, y, image.getRGB((int) Math.floor(x * scale), (int) Math.floor(y * scale)));
					}
					catch (final ArrayIndexOutOfBoundsException e)
					{
						continue;
					}
				}
			}
		
		g.drawImage(newImage, 0, 0, null);
	}
	
	/**
	 * Returns the preferred size of the component
	 * @return the preferred dimension
	 */
	public Dimension getPreferredSize()
	{
		return new Dimension(width, height);
	}
	
	public void setMaxDim (final Dimension dim)
	{
		height = (int) dim.getHeight();
		width = (int) dim.getWidth();
		this.setMaximumSize(dim);
		this.setMinimumSize(dim);
		this.setPreferredSize(dim);
		this.setSize(dim);
	}
		
	public void addPhotoPanelListener (final PhotoPanelListener li)
	{
		listeners.add(li);
	}
	
	public void removePhotoPanelListener (final PhotoPanelListener li)
	{
		listeners.remove(li);
	}
	
	public void clearPhotoPanelListeners ()
	{
		listeners.clear();
	}
	
	private void firePhotoAdded (final Photo photo)
	{
		for (final PhotoPanelListener li : listeners)
			li.photoAdded(this, photo);
	}
	
	private void firePhotoRemoved (final Photo photo)
	{
		for (final PhotoPanelListener li : listeners)
			li.photoRemoved(this, photo);
	}
	
	public void fireSetPreview (final Photo photo)
	{
		for (final PhotoPanelListener li : listeners)
			li.setPreview(this,photo);
	}
	
	private void fireNewContentDisplayed (final Photo photo)
	{
		for (final PhotoPanelListener li : listeners)
			li.newContentDisplayed(this, photo);
	}
	
	public void removeContent ()
	{
		final Photo photo = getContent();
		setContent(null);
		firePhotoRemoved(photo);
	}
	
	public void enableDrag ()
	{		
		
		final DragSource source = new DragSource();
		final DragGestureListener manager = new DragGestureListener () {
			public void dragGestureRecognized (final DragGestureEvent dge) {
				if (content == null || dge.getDragAction() != DnDConstants.ACTION_MOVE)
					return;
				dge.startDrag(DragSource.DefaultMoveDrop, content);
			}
		};
		
		source.createDefaultDragGestureRecognizer(this, DnDConstants.ACTION_MOVE, manager);
		source.addDragSourceListener(new DragSourceAdapter() {
			private boolean toRemove = false;
			public void dragExit (final DragSourceEvent ev) { toRemove = false; }
			public void dragOver (final DragSourceDragEvent ev) { toRemove = true; }
			public void dragDropEnd (final DragSourceDropEvent ev) {
				if (toRemove) {
					ItemManager.instance().multimediaDelete(getContent());
					removeContent();
				}
				toRemove = false;
			}
		} );
	}
	
	public void setDropMode (final boolean state)
	{
		if (!state) {
			this.setTransferHandler(null);
			return;
		}

		TransferHandler handler = new TransferHandler() {
			private static final long serialVersionUID = -1L;
			
	        public boolean canImport(TransferHandler.TransferSupport support) {
	            if (!support.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) {
	                return false;
	            }

	            return true;
	        }

	        public boolean importData(TransferHandler.TransferSupport support) {
	            if (!canImport(support)) {
	                return false;
	            }
	            
	            Transferable t = support.getTransferable();

	            try {
	                @SuppressWarnings("unchecked")
	                java.util.List<File> l = (java.util.List<File>) t.getTransferData(DataFlavor.javaFileListFlavor);

	                for (final File f : l) {
	                	final Photo photo = new Photo("", f.getAbsolutePath(), "");
	                	firePhotoAdded(photo);
	                	setContent(photo);
	                }
	            } catch (UnsupportedFlavorException e) {
	                return false;
	            } catch (IOException e) {
	                return false;
	            } catch (ClassCastException e) {
	            	return false;
	            }

	            return true;
	        }
	    };
	    this.setTransferHandler(handler);
	}
	
	private void deleteThis ()
	{
		new PhotoPanelEraseCommand(this).actionPerformed(null);
	}
	
	public void enablePopup ()
	{
		this.addMouseListener(new MouseAdapter () {
			public void mouseEntered (final MouseEvent ev) {
				if (content == null) {
					setToolTipText(null);
					return;
				}
				final String title = content.getTitle();
				final String comment = content.getComment();
				String ttt = "<html>";
				if (title.length() > 0)
					ttt += "<b>Title:</b> " + title;
				if (comment.length() > 0) {
					if (title.length() > 0)
						ttt += "<br>";
					ttt += "<b>Comment:</b> " + comment;
				}
				else if (title.length() <= 0) {
					setToolTipText(null);
					return;
				}
				ttt += "</html>";	
				setToolTipText(ttt);
				}
			public void mousePressed (final MouseEvent ev) { requestFocus(); checkPopup(ev); } 
			public void mouseReleased (final MouseEvent ev) { requestFocus(); checkPopup(ev); }
			private void checkPopup (final MouseEvent ev) { if (ev.isPopupTrigger()) showPopup(ev.getPoint()); }
		});
		this.addKeyListener(new KeyAdapter() {
			public void keyPressed (KeyEvent ev) {
				if (ev.getKeyCode() == KeyEvent.VK_D && ev.getModifiers() == Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()) {
					deleteThis();
				}
			}
		});
	}
	
	private void showPopup (final Point p)
	{
		if (content == null)
			return;
		
		final JPopupMenu popup = new JPopupMenu();
		final JMenuItem setPreview = new JMenuItem(new AbstractAction("Set as preview") {
			private static final long serialVersionUID = -1L;
			public void actionPerformed (final ActionEvent ev) { fireSetPreview(content); }
		});
		final JMenuItem delete = new JMenuItem(new PhotoPanelEraseCommand(this));
		final JMenuItem edit = new JMenuItem(new AbstractAction("Edit") {
			private static final long serialVersionUID = -1L;
			public void actionPerformed (final ActionEvent ev) { new UOMMultimediaEditorDialog(content); }
		});
		
		delete.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_D, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
		popup.add(setPreview);
		popup.addSeparator();
		popup.add(delete);
		popup.addSeparator();
		popup.add(edit);
		popup.show(this, (int) p.getX(), (int) p.getY());
	}
}
